%{
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define YYSTYPE double
extern void yyerror(char const *s);

int Max_top = 1000;
int Max_length_of_string = 100000;
int min_top = 0;
struct _stack{
    int top;
    char data[1000][100000];
};

typedef struct _stack _stack;
void init_stack(_stack *stack){
    int i;
    stack->top = min_top-1;
    for(i = 0; i < Max_top; i++)
        memset(stack->data[i], 0, sizeof(char) * Max_length_of_string);
}
int push_to_stack(_stack *stack, char *InItem){
    stack->top++;
    if(stack->top > Max_top-1)
        return 1;
    sprintf(stack->data[stack->top], "%s", InItem);
    return 0;
}
int pop_from_stack(_stack *stack, char *OutItem){
    if(stack->top < min_top)
        return 1;
    sprintf(OutItem, "%s", stack->data[stack->top--]);
    return 0;
}
 int i;
 int array_size;
_stack arith;
_stack var;
_stack assign;
_stack logic_stack;
_stack expr_stack;
_stack atrb;
_stack arg;
_stack declaration;
_stack type;
char tmp1[100000];
char tmp2[100000];
char tmp3[100000];
char tmp4[100000];
char tmp5[100000];
char array_id[10000];
char * token;
%}
%token NUMBER DIST POSITION DIRECTION DISTANCE CONSTANT IDENTIFIER ATTRIBUTE
%token NL  OR_OP AND_OP EQ_OP NE_OP GE_OP LE_OP TYPE
%left OR_OP
%left AND_OP
%left EQ_OP NE_OP
%left '>' '<' GE_OP LE_OP
%left '+' '-'
%left '*' '/' '%'
%right UMINUS

%%

lines : lines expr ';' {   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
			    pop_from_stack(&expr_stack, tmp1);
			    printf("%s\n", tmp1); }
    ;

expr : assignment_expr  {   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                            pop_from_stack(&assign, tmp1);
                            push_to_stack(&expr_stack, tmp1);
                        }

    | variable_declaration_list { memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                            pop_from_stack(&declaration, tmp1);
                            push_to_stack(&expr_stack, tmp1);

                            }

    | logic_expr        {   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                            pop_from_stack(&logic_stack, tmp1);
                            push_to_stack(&expr_stack, tmp1);
                        }

    ;



variable_declaration_list : variable_declaration 
    | variable_declaration_list variable_declaration {  memset(tmp1, 0, sizeof(char)*Max_length_of_string);
							memset(tmp2, 0, sizeof(char)*Max_length_of_string);
							memset(tmp3, 0, sizeof(char)*Max_length_of_string);
							pop_from_stack(&declaration, tmp1);
							pop_from_stack(&declaration, tmp2);
							sprintf(tmp3, "%s%s", tmp2, tmp1);
							push_to_stack(&declaration, tmp3);

							}
    ;


variable_declaration : type_specifier init_declarator_list';' {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
								memset(tmp2, 0, sizeof(char)*Max_length_of_string);
								memset(tmp3, 0, sizeof(char)*Max_length_of_string);
								memset(tmp4, 0, sizeof(char)*Max_length_of_string);
								memset(tmp5, 0, sizeof(char)*Max_length_of_string);
								memset(array_id, 0, sizeof(char)*Max_length_of_string);
								pop_from_stack(&declaration, tmp1);
								strcpy(tmp5,tmp1);
								pop_from_stack(&type, tmp2);
								token = strtok (tmp5," ,");
								while (token != NULL){
								    if(token[strlen(token)-1] == ']'){
									for(i = 0 ; i < strlen(token) && token[i] != '[' ; i++)
									    array_id[i] = token[i];
									token[strlen(token)-1] = '\0'; 
									sscanf((token+i+1), "%d", &array_size);
									sprintf(tmp3, "%s[]  %s = new %s[%d] ;\n", tmp2, array_id, tmp2, array_size);
									sprintf(tmp4,"%s %s ",tmp4,tmp3);
									for (i=0; i< array_size; i++){
						    sprintf(tmp3, "%s[%d] = new %s() ;\n Mat.addNode(%s[%d]);\n",array_id, i, tmp2, array_id, i);
						    sprintf(tmp4,"%s %s ",tmp4,tmp3);
					    				}
								    }else {
									sprintf(tmp3, "%s  %s = new %s() ;\n Mat.addNode(%s);\n", tmp2, token, tmp2, token);
									sprintf(tmp4,"%s %s ",tmp4,tmp3);
								    }
								    token = strtok (NULL," ,");
								}
								push_to_stack(&declaration,tmp4);
							       };

init_declarator_list:	variable    {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
					pop_from_stack(&var, tmp1);
					push_to_stack(&declaration,tmp1);
				    }
    |	init_declarator_list','variable{    memset(tmp1, 0, sizeof(char)*Max_length_of_string);
					    memset(tmp2, 0, sizeof(char)*Max_length_of_string);
					    memset(tmp3, 0, sizeof(char)*Max_length_of_string);
					    pop_from_stack(&var, tmp1);
					    pop_from_stack(&declaration, tmp2);
					    sprintf(tmp3, "%s, %s", tmp2, tmp1);
					    push_to_stack(&declaration,tmp3);
					}
    ;
										

type_specifier :    TYPE {	memset(tmp3, 0, sizeof(char)*Max_length_of_string);
				sprintf(tmp3, "%s", yylval);
				if (strcmp("#",tmp3)==0){
				    sprintf(tmp3,"int");
				}else if (strcmp("doc",tmp3)==0){
				    sprintf(tmp3,"MDoc");
				}else if (strcmp("pic",tmp3)==0){
				    sprintf(tmp3,"MPic");
				}else if (strcmp("obj",tmp3)==0){
				    sprintf(tmp3,"MObject");
				}else if (strcmp("string",tmp3)==0){
				    sprintf(tmp3,"String");
				}else if (strcmp("label",tmp3)==0){
				    sprintf(tmp3,"MLabel");
				}
				push_to_stack(&type, tmp3);
			    }
		;
assignment_expr : variable '=' re_assignment_expr {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
							memset(tmp2, 0, sizeof(char)*Max_length_of_string);
							memset(tmp3, 0, sizeof(char)*Max_length_of_string);
							pop_from_stack(&var, tmp1);
							pop_from_stack(&assign, tmp2);
							sprintf(tmp3, "%s = %s", tmp1, tmp2);
							push_to_stack(&assign, tmp3);
						    }

    ;

re_assignment_expr : assignment_expr
    | logic_expr	{	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
				pop_from_stack(&logic_stack, tmp1);
				push_to_stack(&assign, tmp1);
			}

    ;
logic_expr: logic_expr OR_OP logic_expr	{   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s || %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
					}
        | logic_expr AND_OP logic_expr	{   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s && %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
					}
	| logic_expr EQ_OP logic_expr	{   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s == %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
					}
	| logic_expr NE_OP logic_expr	{       memset(tmp1, 0, sizeof(char)*Max_length_of_string);
						memset(tmp2, 0, sizeof(char)*Max_length_of_string);
						memset(tmp3, 0, sizeof(char)*Max_length_of_string);
						pop_from_stack(&logic_stack, tmp2);
						pop_from_stack(&logic_stack, tmp1);
						sprintf(tmp3, "%s != %s", tmp1, tmp2);
						push_to_stack(&logic_stack, tmp3);
					}
	| logic_expr '>' logic_expr {       memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s > %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
                                    }
	| logic_expr '<' logic_expr {       memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                                            pop_from_stack(&logic_stack, tmp2);
                                            pop_from_stack(&logic_stack, tmp1);
                                            sprintf(tmp3, "%s < %s", tmp1, tmp2);
                                            push_to_stack(&logic_stack, tmp3);
                                    } 
	| logic_expr GE_OP logic_expr	{       memset(tmp1, 0, sizeof(char)*Max_length_of_string);
			                        memset(tmp2, 0, sizeof(char)*Max_length_of_string);
						memset(tmp3, 0, sizeof(char)*Max_length_of_string);
						pop_from_stack(&logic_stack, tmp2);
						pop_from_stack(&logic_stack, tmp1);
						sprintf(tmp3, "%s >= %s", tmp1, tmp2);
						push_to_stack(&logic_stack, tmp3);
					}
	| logic_expr LE_OP logic_expr	{       memset(tmp1, 0, sizeof(char)*Max_length_of_string);
			                        memset(tmp2, 0, sizeof(char)*Max_length_of_string);
						memset(tmp3, 0, sizeof(char)*Max_length_of_string);
						pop_from_stack(&logic_stack, tmp2);
						pop_from_stack(&logic_stack, tmp1);
						sprintf(tmp3, "%s <= %s", tmp1, tmp2);
						push_to_stack(&logic_stack, tmp3);
					}
	| arithmetc_expr    {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
				pop_from_stack(&arith, tmp1);
				push_to_stack(&logic_stack, tmp1);
			    }
	;


arithmetc_expr : arithmetc_expr '+' arithmetc_expr	{   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
			    memset(tmp2, 0, sizeof(char)*Max_length_of_string);
			    memset(tmp3, 0, sizeof(char)*Max_length_of_string);
			    pop_from_stack(&arith, tmp2);
			    pop_from_stack(&arith, tmp1);
			    sprintf(tmp3, "%s + %s", tmp1, tmp2);
			    push_to_stack(&arith, tmp3); 
			}
    | arithmetc_expr '-' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp3, 0, sizeof(char)*Max_length_of_string);
			pop_from_stack(&arith, tmp2);
                        pop_from_stack(&arith, tmp1);
                        sprintf(tmp3, "%s - %s", tmp1, tmp2);
                        push_to_stack(&arith, tmp3);
		    }
    | arithmetc_expr '*' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp3, 0, sizeof(char)*Max_length_of_string);
			pop_from_stack(&arith, tmp2);
                        pop_from_stack(&arith, tmp1);
                        sprintf(tmp3, "%s * %s", tmp1, tmp2);
                        push_to_stack(&arith, tmp3); 
		    }
    | arithmetc_expr '/' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp3, 0, sizeof(char)*Max_length_of_string);
			pop_from_stack(&arith, tmp2);
			pop_from_stack(&arith, tmp1);
			sprintf(tmp3, "%s / %s", tmp1, tmp2);
			push_to_stack(&arith, tmp3);
		    }
    | arithmetc_expr '%' arithmetc_expr {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp2, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp3, 0, sizeof(char)*Max_length_of_string);
			pop_from_stack(&arith, tmp2);
			pop_from_stack(&arith, tmp1);
			sprintf(tmp3, "%s %s %s", tmp1,"%" ,tmp2);
			push_to_stack(&arith, tmp3);
		    }
    | '!' arithmetc_expr %prec UMINUS   {   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                                            memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                                            pop_from_stack(&arith, tmp1);
                                            sprintf(tmp3, " !%s ", tmp1);
                                            push_to_stack(&arith, tmp3);
                                        }

    | '-' arithmetc_expr %prec UMINUS {   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
				memset(tmp3, 0, sizeof(char)*Max_length_of_string);
				pop_from_stack(&arith, tmp1);
				sprintf(tmp3, " -%s ", tmp1);
				push_to_stack(&arith, tmp3);
			    }
    | variable  {	memset(tmp1, 0, sizeof(char)*Max_length_of_string);
			memset(tmp3, 0, sizeof(char)*Max_length_of_string);
			pop_from_stack(&var, tmp1);
			sprintf(tmp3, "%s", tmp1);
			push_to_stack(&arith, tmp3);
		}
    ;
atrbut :    ATTRIBUTE {   memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                            sprintf(tmp3, "%s", yylval);
                            push_to_stack(&atrb, tmp3);
                        }
    ;
argument_expression_list : logic_expr	{   memset(tmp3, 0, sizeof(char)*Max_length_of_string);
					    pop_from_stack(&logic_stack, tmp3);
					    push_to_stack(&arg, tmp3);

					}
    | argument_expression_list ',' logic_expr	{   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
						    memset(tmp3, 0, sizeof(char)*Max_length_of_string);
						    memset(tmp2, 0, sizeof(char)*Max_length_of_string);
						    pop_from_stack(&arg, tmp1);
						    pop_from_stack(&logic_stack, tmp2);
						    sprintf(tmp3, "%s,%s", tmp1, tmp2);
						    push_to_stack(&arg, tmp3);
						}
variable    : IDENTIFIER    {	memset(tmp3, 0, sizeof(char)*Max_length_of_string);
				sprintf(tmp3, "%s", yylval);
				push_to_stack(&var, tmp3);
			    }	     
	    | variable '.' atrbut  {	    memset(tmp1, 0, sizeof(char)*Max_length_of_string);
					    memset(tmp3, 0, sizeof(char)*Max_length_of_string);
					    memset(tmp2, 0, sizeof(char)*Max_length_of_string);
					    pop_from_stack(&var, tmp1);
					    pop_from_stack(&atrb, tmp2);
					    sprintf(tmp3, "%s.%s", tmp1, tmp2);
					    push_to_stack(&var, tmp3);
					}

	    | variable '[' arithmetc_expr ']' {   memset(tmp1, 0, sizeof(char)*Max_length_of_string);
					memset(tmp2, 0, sizeof(char)*Max_length_of_string);
					memset(tmp3, 0, sizeof(char)*Max_length_of_string);
					pop_from_stack(&arith, tmp1);
					pop_from_stack(&var, tmp2);
					sprintf(tmp3, "%s[%s]", tmp2, tmp1);
					push_to_stack(&var, tmp3);
				    }

	    | variable '(' ')'  {   memset(tmp3, 0, sizeof(char)*Max_length_of_string);
				    memset(tmp1, 0, sizeof(char)*Max_length_of_string);
				    pop_from_stack(&var, tmp1);
				    if((strcmp(tmp1, "from") == 0) || (strcmp(tmp1, "degree") == 0) || (strcmp(tmp1, "distance") == 0)){
                                        sprintf(tmp3, "Mat.%s()", tmp1);
                                    }else if((strcmp(tmp1, "poly") == 0) || (strcmp(tmp1, "text") == 0) || (strcmp(tmp1, "layout") == 0)) {
                                        sprintf(tmp3, "Mat.%s()", tmp1);
                                    }else
					sprintf(tmp3, "%s()", tmp1);
				    push_to_stack(&var, tmp3);
				}
	    | variable '('argument_expression_list ')'  {   memset(tmp3, 0, sizeof(char)*Max_length_of_string);
				    memset(tmp2, 0, sizeof(char)*Max_length_of_string);
				    memset(tmp1, 0, sizeof(char)*Max_length_of_string);
				    pop_from_stack(&var, tmp1);
				    pop_from_stack(&arg, tmp2);
				    if((strcmp(tmp1, "from") == 0) || (strcmp(tmp1, "degree") == 0) || (strcmp(tmp1, "distance") == 0)){
					sprintf(tmp3, "Mat.%s(%s)", tmp1, tmp2);
				    }else if((strcmp(tmp1, "poly") == 0) || (strcmp(tmp1, "text") == 0) || (strcmp(tmp1, "layout") == 0)) {
					sprintf(tmp3, "Mat.%s(%s)", tmp1, tmp2);
				    }else
					sprintf(tmp3, "%s(%s)", tmp1, tmp2);
				    push_to_stack(&var, tmp3);
				}
	    | CONSTANT	{   memset(tmp3, 0, sizeof(char)*Max_length_of_string);
			    sprintf(tmp3, "%s", yylval);
			    push_to_stack(&var, tmp3);
			}

	    | '(' logic_expr ')'  {     memset(tmp1, 0, sizeof(char)*Max_length_of_string);
                        memset(tmp3, 0, sizeof(char)*Max_length_of_string);
                        pop_from_stack(&logic_stack, tmp1);
                        sprintf(tmp3, "( %s )", tmp1);
                        push_to_stack(&var, tmp3);
                    }


%%


int yywrap(void){
    return 0;
}
void yyerror(char const *s){
    fprintf(stderr, "%s\n", s);
}
int main(void){
    init_stack(&arith);
    init_stack(&var);
    init_stack(&arg);
    init_stack(&assign);
    init_stack(&atrb);
    init_stack(&expr_stack);
    init_stack(&declaration);
    init_stack(&type);
    yyparse();

    return 0;
}
